/*
 * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
 * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* ScriptData
 SDName: Stormwind_City
 SD%Complete: 100
 SDComment: Quest support: 1640, 1447, 4185, 11223, 434.
 SDCategory: Stormwind City
 EndScriptData */

/* ContentData
 npc_archmage_malin
 npc_bartleby
 npc_dashel_stonefist
 npc_lady_katrana_prestor
 npc_tyrion
 npc_tyrion_spybot
 npc_marzon_silent_blade
 npc_lord_gregor_lescovar
 EndContentData */

#include "ScriptPCH.h"
#include "ScriptedEscortAI.h"

/*######
 ## npc_archmage_malin
 ######*/

#define GOSSIP_ITEM_MALIN "Can you send me to Theramore? I have an urgent message for Lady Jaina from Highlord Bolvar."

class npc_archmage_malin: public CreatureScript {
public:
    npc_archmage_malin() :
            CreatureScript("npc_archmage_malin") {
    }

    bool OnGossipSelect(Player* pPlayer, Creature* pCreature,
            uint32 /*uiSender*/, uint32 uiAction) {
        pPlayer->PlayerTalkClass->ClearMenus();
        if (uiAction == GOSSIP_ACTION_INFO_DEF) {
            pPlayer->CLOSE_GOSSIP_MENU();
            pCreature->CastSpell(pPlayer, 42711, true);
        }

        return true;
    }

    bool OnGossipHello(Player* pPlayer, Creature* pCreature) {
        if (pCreature->isQuestGiver())
            pPlayer->PrepareQuestMenu(pCreature->GetGUID());

        if (pPlayer->GetQuestStatus(11223) == QUEST_STATUS_COMPLETE)
            pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MALIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);

        pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID());

        return true;
    }
};

/*######
 ## npc_bartleby
 ######*/

enum eBartleby {
    FACTION_ENEMY = 168, QUEST_BEAT = 1640
};

class npc_bartleby: public CreatureScript {
public:
    npc_bartleby() :
            CreatureScript("npc_bartleby") {
    }

    bool OnQuestAccept(Player* pPlayer, Creature* pCreature,
            Quest const* pQuest) {
        if (pQuest->GetQuestId() == QUEST_BEAT) {
            pCreature->setFaction(FACTION_ENEMY);
            pCreature->AI()->AttackStart(pPlayer);
        }
        return true;
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_bartlebyAI(pCreature);
    }

    struct npc_bartlebyAI: public ScriptedAI {
        npc_bartlebyAI(Creature *c) :
                ScriptedAI(c) {
            m_uiNormalFaction = c->getFaction();
        }

        uint32 m_uiNormalFaction;

        void Reset() {
            if (me->getFaction() != m_uiNormalFaction)
                me->setFaction(m_uiNormalFaction);
        }

        void AttackedBy(Unit* pAttacker) {
            if (me->getVictim())
                return;

            if (me->IsFriendlyTo(pAttacker))
                return;

            AttackStart(pAttacker);
        }

        void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) {
            if (uiDamage > me->GetHealth()
                    || me->HealthBelowPctDamaged(15, uiDamage)) {
                //Take 0 damage
                uiDamage = 0;

                if (pDoneBy->GetTypeId() == TYPEID_PLAYER)
                    CAST_PLR(pDoneBy)->AreaExploredOrEventHappens(QUEST_BEAT);
                EnterEvadeMode();
            }
        }
    };
};

/*######
 ## npc_dashel_stonefist
 ######*/

enum eDashel {
    QUEST_MISSING_DIPLO_PT8 = 1447, FACTION_HOSTILE = 168
};

class npc_dashel_stonefist: public CreatureScript {
public:
    npc_dashel_stonefist() :
            CreatureScript("npc_dashel_stonefist") {
    }

    bool OnQuestAccept(Player* pPlayer, Creature* pCreature,
            Quest const* pQuest) {
        if (pQuest->GetQuestId() == QUEST_MISSING_DIPLO_PT8) {
            pCreature->setFaction(FACTION_HOSTILE);
            CAST_AI(npc_dashel_stonefist::npc_dashel_stonefistAI, pCreature->AI())->AttackStart(
                    pPlayer);
        }
        return true;
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_dashel_stonefistAI(pCreature);
    }

    struct npc_dashel_stonefistAI: public ScriptedAI {
        npc_dashel_stonefistAI(Creature *c) :
                ScriptedAI(c) {
            m_uiNormalFaction = c->getFaction();
        }

        uint32 m_uiNormalFaction;

        void Reset() {
            if (me->getFaction() != m_uiNormalFaction)
                me->setFaction(m_uiNormalFaction);
        }

        void AttackedBy(Unit* pAttacker) {
            if (me->getVictim())
                return;

            if (me->IsFriendlyTo(pAttacker))
                return;

            AttackStart(pAttacker);
        }

        void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) {
            if (uiDamage > me->GetHealth()
                    || me->HealthBelowPctDamaged(15, uiDamage)) {
                uiDamage = 0;

                if (pDoneBy->GetTypeId() == TYPEID_PLAYER)
                    CAST_PLR(pDoneBy)->AreaExploredOrEventHappens(
                            QUEST_MISSING_DIPLO_PT8);

                EnterEvadeMode();
            }
        }
    };
};

/*######
 ## npc_lady_katrana_prestor
 ######*/

#define GOSSIP_ITEM_KAT_1 "Pardon the intrusion, Lady Prestor, but Highlord Bolvar suggested that I seek your advice."
#define GOSSIP_ITEM_KAT_2 "My apologies, Lady Prestor."
#define GOSSIP_ITEM_KAT_3 "Begging your pardon, Lady Prestor. That was not my intent."
#define GOSSIP_ITEM_KAT_4 "Thank you for your time, Lady Prestor."

class npc_lady_katrana_prestor: public CreatureScript {
public:
    npc_lady_katrana_prestor() :
            CreatureScript("npc_lady_katrana_prestor") {
    }

    bool OnGossipSelect(Player* pPlayer, Creature* pCreature,
            uint32 /*uiSender*/, uint32 uiAction) {
        pPlayer->PlayerTalkClass->ClearMenus();
        switch (uiAction) {
        case GOSSIP_ACTION_INFO_DEF:
            pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
            pPlayer->SEND_GOSSIP_MENU(2694, pCreature->GetGUID());
            break;
        case GOSSIP_ACTION_INFO_DEF + 1:
            pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
            pPlayer->SEND_GOSSIP_MENU(2695, pCreature->GetGUID());
            break;
        case GOSSIP_ACTION_INFO_DEF + 2:
            pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
            pPlayer->SEND_GOSSIP_MENU(2696, pCreature->GetGUID());
            break;
        case GOSSIP_ACTION_INFO_DEF + 3:
            pPlayer->CLOSE_GOSSIP_MENU();
            pPlayer->AreaExploredOrEventHappens(4185);
            break;
        }
        return true;
    }

    bool OnGossipHello(Player* pPlayer, Creature* pCreature) {
        if (pCreature->isQuestGiver())
            pPlayer->PrepareQuestMenu(pCreature->GetGUID());

        if (pPlayer->GetQuestStatus(4185) == QUEST_STATUS_INCOMPLETE)
            pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);

        pPlayer->SEND_GOSSIP_MENU(2693, pCreature->GetGUID());

        return true;
    }
};

/*######
 ## npc_lord_gregor_lescovar
 ######*/

enum eLordGregorLescovar {
    SAY_LESCOVAR_2 = -1000457,
    SAY_GUARD_2 = -1000458,
    SAY_LESCOVAR_3 = -1000459,
    SAY_MARZON_1 = -1000460,
    SAY_LESCOVAR_4 = -1000461,
    SAY_TYRION_2 = -1000462,
    SAY_MARZON_2 = -1000463,

    NPC_STORMWIND_ROYAL = 1756,
    NPC_MARZON_BLADE = 1755,
    NPC_TYRION = 7766,

    QUEST_THE_ATTACK = 434
};

class npc_lord_gregor_lescovar: public CreatureScript {
public:
    npc_lord_gregor_lescovar() :
            CreatureScript("npc_lord_gregor_lescovar") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_lord_gregor_lescovarAI(pCreature);
    }

    struct npc_lord_gregor_lescovarAI: public npc_escortAI {
        npc_lord_gregor_lescovarAI(Creature* pCreature) :
                npc_escortAI(pCreature) {
            pCreature->RestoreFaction();
        }

        uint32 uiTimer;
        uint32 uiPhase;

        uint64 MarzonGUID;

        void Reset() {
            uiTimer = 0;
            uiPhase = 0;

            MarzonGUID = 0;
        }

        void EnterEvadeMode() {
            me->DisappearAndDie();

            if (Creature *pMarzon = Unit::GetCreature(*me, MarzonGUID)) {
                if (pMarzon->isAlive())
                    pMarzon->DisappearAndDie();
            }
        }

        void EnterCombat(Unit* pWho) {
            if (Creature *pMarzon = Unit::GetCreature(*me, MarzonGUID)) {
                if (pMarzon->isAlive() && !pMarzon->isInCombat())
                    pMarzon->AI()->AttackStart(pWho);
            }
        }

        void WaypointReached(uint32 uiPointId) {
            switch (uiPointId) {
            case 14:
                SetEscortPaused(true);
                DoScriptText(SAY_LESCOVAR_2, me);
                uiTimer = 3000;
                uiPhase = 1;
                break;
            case 16:
                SetEscortPaused(true);
                if (Creature *pMarzon = me->SummonCreature(NPC_MARZON_BLADE, -8411.360352f, 480.069733f, 123.760895f, 4.941504f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000)) {
                    pMarzon->GetMotionMaster()->MovePoint(0, -8408.000977f,
                            468.611450f, 123.759903f);
                    MarzonGUID = pMarzon->GetGUID();
                }
                uiTimer = 2000;
                uiPhase = 4;
                break;
            }
        }
        //TO-DO: We don't have movemaps, also we can't make 2 npcs walks to one point propperly (and we can not use escort ai, because they are 2 different spawns and with same entry), because of it we make them, disappear.
        void DoGuardsDisappearAndDie() {
            std::list<Creature*> GuardList;
            me->GetCreatureListWithEntryInGrid(GuardList, NPC_STORMWIND_ROYAL,
                    8.0f);
            if (!GuardList.empty()) {
                for (std::list<Creature*>::const_iterator itr =
                        GuardList.begin(); itr != GuardList.end(); ++itr) {
                    if (Creature* pGuard = *itr)
                        pGuard->DisappearAndDie();
                }
            }
        }

        void UpdateAI(const uint32 uiDiff) {
            if (uiPhase) {
                if (uiTimer <= uiDiff) {
                    switch (uiPhase) {
                    case 1:
                        if (Creature* pGuard = me->FindNearestCreature(NPC_STORMWIND_ROYAL, 8.0f, true))
                            DoScriptText(SAY_GUARD_2, pGuard);
                        uiTimer = 3000;
                        uiPhase = 2;
                        break;
                    case 2:
                        DoGuardsDisappearAndDie();
                        uiTimer = 2000;
                        uiPhase = 3;
                        break;
                    case 3:
                        SetEscortPaused(false);
                        uiTimer = 0;
                        uiPhase = 0;
                        break;
                    case 4:
                        DoScriptText(SAY_LESCOVAR_3, me);
                        uiTimer = 0;
                        uiPhase = 0;
                        break;
                    case 5:
                        if (Creature *pMarzon = Unit::GetCreature(*me, MarzonGUID))
                            DoScriptText(SAY_MARZON_1, pMarzon);
                        uiTimer = 3000;
                        uiPhase = 6;
                        break;
                    case 6:
                        DoScriptText(SAY_LESCOVAR_4, me);
                        if (Player* pPlayer = GetPlayerForEscort())
                            pPlayer->AreaExploredOrEventHappens(
                                    QUEST_THE_ATTACK);
                        uiTimer = 2000;
                        uiPhase = 7;
                        break;
                    case 7:
                        if (Creature* pTyrion = me->FindNearestCreature(NPC_TYRION, 20.0f, true))
                            DoScriptText(SAY_TYRION_2, pTyrion);
                        if (Creature *pMarzon = Unit::GetCreature(*me, MarzonGUID))
                            pMarzon->setFaction(14);
                        me->setFaction(14);
                        uiTimer = 0;
                        uiPhase = 0;
                        break;
                    }
                } else
                    uiTimer -= uiDiff;
            }
            npc_escortAI::UpdateAI(uiDiff);

            if (!UpdateVictim())
                return;

            DoMeleeAttackIfReady();
        }
    };
};

/*######
 ## npc_marzon_silent_blade
 ######*/

class npc_marzon_silent_blade: public CreatureScript {
public:
    npc_marzon_silent_blade() :
            CreatureScript("npc_marzon_silent_blade") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_marzon_silent_bladeAI(pCreature);
    }

    struct npc_marzon_silent_bladeAI: public ScriptedAI {
        npc_marzon_silent_bladeAI(Creature* pCreature) :
                ScriptedAI(pCreature) {
            me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
        }

        void Reset() {
            me->RestoreFaction();
        }

        void EnterCombat(Unit* pWho) {
            DoScriptText(SAY_MARZON_2, me);

            if (me->isSummon()) {
                if (Unit* pSummoner = CAST_SUM(me)->GetSummoner()) {
                    if (pSummoner && pSummoner->isAlive()
                            && !pSummoner->isInCombat())
                        CAST_CRE(pSummoner)->AI()->AttackStart(pWho);
                }
            }
        }

        void EnterEvadeMode() {
            me->DisappearAndDie();

            if (me->isSummon()) {
                if (Unit* pSummoner = CAST_SUM(me)->GetSummoner()) {
                    if (pSummoner && pSummoner->isAlive())
                        CAST_CRE(pSummoner)->DisappearAndDie();
                }
            }
        }

        void MovementInform(uint32 uiType, uint32 /*uiId*/) {
            if (uiType != POINT_MOTION_TYPE)
                return;

            if (me->isSummon()) {
                if (Unit* pSummoner = CAST_SUM(me)->GetSummoner()) {
                    CAST_AI(npc_lord_gregor_lescovar::npc_lord_gregor_lescovarAI, CAST_CRE(pSummoner)->AI())->uiTimer =
                            2000;
                    CAST_AI(npc_lord_gregor_lescovar::npc_lord_gregor_lescovarAI, CAST_CRE(pSummoner)->AI())->uiPhase =
                            5;
                    //me->ChangeOrient(0.0f, pSummoner);
                }
            }
        }

        void UpdateAI(const uint32 /*diff*/) {
            if (!UpdateVictim())
                return;

            DoMeleeAttackIfReady();
        }
    };
};

/*######
 ## npc_tyrion_spybot
 ######*/

enum eTyrionSpybot {
    SAY_QUEST_ACCEPT_ATTACK = -1000499,
    SAY_TYRION_1 = -1000450,
    SAY_SPYBOT_1 = -1000451,
    SAY_GUARD_1 = -1000452,
    SAY_SPYBOT_2 = -1000453,
    SAY_SPYBOT_3 = -1000454,
    SAY_LESCOVAR_1 = -1000455,
    SAY_SPYBOT_4 = -1000456,

    NPC_PRIESTESS_TYRIONA = 7779,
    NPC_LORD_GREGOR_LESCOVAR = 1754,
};

class npc_tyrion_spybot: public CreatureScript {
public:
    npc_tyrion_spybot() :
            CreatureScript("npc_tyrion_spybot") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_tyrion_spybotAI(pCreature);
    }

    struct npc_tyrion_spybotAI: public npc_escortAI {
        npc_tyrion_spybotAI(Creature* pCreature) :
                npc_escortAI(pCreature) {
        }

        uint32 uiTimer;
        uint32 uiPhase;

        void Reset() {
            uiTimer = 0;
            uiPhase = 0;
        }

        void WaypointReached(uint32 uiPointId) {
            switch (uiPointId) {
            case 1:
                SetEscortPaused(true);
                uiTimer = 2000;
                uiPhase = 1;
                break;
            case 5:
                SetEscortPaused(true);
                DoScriptText(SAY_SPYBOT_1, me);
                uiTimer = 2000;
                uiPhase = 5;
                break;
            case 17:
                SetEscortPaused(true);
                DoScriptText(SAY_SPYBOT_3, me);
                uiTimer = 3000;
                uiPhase = 8;
                break;
            }
        }

        void UpdateAI(const uint32 uiDiff) {
            if (uiPhase) {
                if (uiTimer <= uiDiff) {
                    switch (uiPhase) {
                    case 1:
                        DoScriptText(SAY_QUEST_ACCEPT_ATTACK, me);
                        uiTimer = 3000;
                        uiPhase = 2;
                        break;
                    case 2:
                        if (Creature* pTyrion = me->FindNearestCreature(NPC_TYRION, 10.0f))
                            DoScriptText(SAY_TYRION_1, pTyrion);
                        uiTimer = 3000;
                        uiPhase = 3;
                        break;
                    case 3:
                        me->UpdateEntry(NPC_PRIESTESS_TYRIONA, ALLIANCE);
                        uiTimer = 2000;
                        uiPhase = 4;
                        break;
                    case 4:
                        SetEscortPaused(false);
                        uiPhase = 0;
                        uiTimer = 0;
                        break;
                    case 5:
                        if (Creature* pGuard = me->FindNearestCreature(NPC_STORMWIND_ROYAL, 10.0f, true))
                            DoScriptText(SAY_GUARD_1, pGuard);
                        uiTimer = 3000;
                        uiPhase = 6;
                        break;
                    case 6:
                        DoScriptText(SAY_SPYBOT_2, me);
                        uiTimer = 3000;
                        uiPhase = 7;
                        break;
                    case 7:
                        SetEscortPaused(false);
                        uiTimer = 0;
                        uiPhase = 0;
                        break;
                    case 8:
                        if (Creature* pLescovar = me->FindNearestCreature(NPC_LORD_GREGOR_LESCOVAR, 10.0f))
                            DoScriptText(SAY_LESCOVAR_1, pLescovar);
                        uiTimer = 3000;
                        uiPhase = 9;
                        break;
                    case 9:
                        DoScriptText(SAY_SPYBOT_4, me);
                        uiTimer = 3000;
                        uiPhase = 10;
                        break;
                    case 10:
                        if (Creature* pLescovar = me->FindNearestCreature(NPC_LORD_GREGOR_LESCOVAR, 10.0f)) {
                            if (Player* pPlayer = GetPlayerForEscort()) {
                                CAST_AI(npc_lord_gregor_lescovar::npc_lord_gregor_lescovarAI, pLescovar->AI())->Start(
                                        false, false, pPlayer->GetGUID());
                                CAST_AI(npc_lord_gregor_lescovar::npc_lord_gregor_lescovarAI, pLescovar->AI())->SetMaxPlayerDistance(
                                        200.0f);
                            }
                        }
                        me->DisappearAndDie();
                        uiTimer = 0;
                        uiPhase = 0;
                        break;
                    }
                } else
                    uiTimer -= uiDiff;
            }
            npc_escortAI::UpdateAI(uiDiff);

            if (!UpdateVictim())
                return;

            DoMeleeAttackIfReady();
        }
    };
};

/*######
 ## npc_tyrion
 ######*/

enum eTyrion {
    NPC_TYRION_SPYBOT = 8856
};

class npc_tyrion: public CreatureScript {
public:
    npc_tyrion() :
            CreatureScript("npc_tyrion") {
    }

    bool OnQuestAccept(Player* pPlayer, Creature* pCreature,
            Quest const *pQuest) {
        if (pQuest->GetQuestId() == QUEST_THE_ATTACK) {
            if (Creature* pSpybot = pCreature->FindNearestCreature(NPC_TYRION_SPYBOT, 5.0f, true)) {
                CAST_AI(npc_tyrion_spybot::npc_tyrion_spybotAI, pSpybot->AI())->Start(
                        false, false, pPlayer->GetGUID());
                CAST_AI(npc_tyrion_spybot::npc_tyrion_spybotAI, pSpybot->AI())->SetMaxPlayerDistance(
                        200.0f);
            }
            return true;
        }
        return false;
    }
};

void AddSC_stormwind_city() {
    new npc_archmage_malin();
    new npc_bartleby();
    new npc_dashel_stonefist();
    new npc_lady_katrana_prestor();
    new npc_tyrion();
    new npc_tyrion_spybot();
    new npc_lord_gregor_lescovar();
    new npc_marzon_silent_blade();
}
